﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayden.Dll.PathFinding;
using System.IO;
using Jayden.Dll.Navigation.Core;
using System.Drawing;
using System.Drawing.Imaging;

namespace Jayden.Dll.Navigation.Tools
{
	public sealed class Utils
	{
		private Utils() { }

		public static void Save(string filename, List<PathNode> indexes)
		{
			FileStream fileStream = File.Create(filename);
			BinaryWriter writer = new BinaryWriter(fileStream);
			writer.Write((uint)0xdeadbeaf);
			writer.Write((byte)0x00);
			writer.Write((int)indexes.Count);
			for (int c = 0; c < indexes.Count; c++)
			{
				writer.Write((indexes[c] as Coordinate).Latitude);
				writer.Write((indexes[c] as Coordinate).Longitude);
			}
			foreach (PathNode node in indexes)
			{
				int startIndex = indexes.IndexOf(node);
				foreach (PathInformation path in node.Paths)
				{
					int endIndex = indexes.IndexOf(path.End);
					writer.Write(startIndex);
					writer.Write(endIndex);
				}
			}
			writer.Flush();
			writer.Close();
		}

		public static List<PathNode> Load(string filename)
		{
			List<PathNode> indexes = new List<PathNode>();
			if (!File.Exists(filename))
				return indexes;
			FileStream fileStream = File.OpenRead(filename);
			BinaryReader reader = new BinaryReader(fileStream);
			uint header = reader.ReadUInt32();
			if (header != 0xdeadbeaf)
				throw new Exception("Invalid file.");
			byte version = reader.ReadByte();
			if (version != 0x00)
				throw new Exception("Invalid file version.");
			int count = reader.ReadInt32();
			for (int c = 0; c < count; c++)
			{
				double lat = reader.ReadDouble();
				double lng = reader.ReadDouble();
				Coordinate coord = new Coordinate(lat, lng);
				indexes.Add(coord);
			}

			try
			{
				while (true)
				{
					int startIndex = reader.ReadInt32();
					int endIndex = reader.ReadInt32();
					Way pathInformation = new Way(indexes[startIndex] as Coordinate, indexes[endIndex] as Coordinate);
				}
			}
			catch (EndOfStreamException eos) { }

			reader.Close();

			return indexes;
		}

		public static void SaveImage(string filename, int pixelWidth, List<PathNode> all, List<PathInformation> shortestPath)
		{

			double minLatitude = double.MaxValue;
			double minLongitude = double.MaxValue;
			double maxLatitude = double.MinValue;
			double maxLongitude = double.MinValue;

			HashSet<PathNode> nodes = new HashSet<PathNode>();

			foreach (PathNode node in all)
			{
				nodes.Add(node);
				if (node is Coordinate)
				{
					Coordinate coord = node as Coordinate;
					minLatitude = Math.Min(minLatitude, coord.Latitude);
					minLongitude = Math.Min(minLongitude, coord.Longitude);
					maxLatitude = Math.Max(maxLatitude, coord.Latitude);
					maxLongitude = Math.Max(maxLongitude, coord.Longitude);
				}
			}


			double width = maxLongitude - minLongitude;
			double height = maxLatitude - minLatitude;

			double ratio = width / height;

			int imageWidth = pixelWidth;
			int imageHeight = (int)((1 / ratio) * imageWidth);

			double pixelRatio = pixelWidth / width;

			Bitmap bitmap = new Bitmap(imageWidth, imageHeight);
			SolidBrush backgroundColor = new SolidBrush(Color.White);
			SolidBrush coordinatesColor = new SolidBrush(Color.Red);
			SolidBrush startColor = new SolidBrush(Color.Green);
			SolidBrush endColor = new SolidBrush(Color.Blue);
			Pen pathColor = new Pen(new SolidBrush(Color.Black));
			Pen shortestPathColor = new Pen(new SolidBrush(Color.Green));
			Pen oneWayPathColor = new Pen(new SolidBrush(Color.DarkGray));

			Graphics graphics = Graphics.FromImage(bitmap);
			graphics.FillRectangle(backgroundColor, 0, 0, imageWidth, imageHeight);

			foreach (PathNode node in nodes)
			{
				if (node is Coordinate)
				{
					Coordinate coord = node as Coordinate;
					int y = (int)((coord.Latitude - minLatitude) * pixelRatio);
					int x = (int)((coord.Longitude - minLongitude) * pixelRatio);
					graphics.FillEllipse(coordinatesColor, x - 2, y - 2, 5, 5);
				}
				foreach (PathInformation path in node.Paths)
				{
					if (path.Start is Coordinate && path.End is Coordinate)
					{
						Coordinate start = path.Start as Coordinate;
						Coordinate end = path.End as Coordinate;
						int y = (int)((start.Latitude - minLatitude) * pixelRatio);
						int x = (int)((start.Longitude - minLongitude) * pixelRatio);
						int y2 = (int)((end.Latitude - minLatitude) * pixelRatio);
						int x2 = (int)((end.Longitude - minLongitude) * pixelRatio);
						if (path is CorePathInformation && (path as CorePathInformation).IsOneWay)
							graphics.DrawLine(oneWayPathColor, x, y, x2, y2);
						else
							graphics.DrawLine(pathColor, x, y, x2, y2);
					}
				}
			}
			if (shortestPath != null)
			{
				foreach (PathInformation path in shortestPath)
				{
					if (path.Start is Coordinate && path.End is Coordinate)
					{
						Coordinate start = path.Start as Coordinate;
						Coordinate end = path.End as Coordinate;
						int y = (int)((start.Latitude - minLatitude) * pixelRatio);
						int x = (int)((start.Longitude - minLongitude) * pixelRatio);
						int y2 = (int)((end.Latitude - minLatitude) * pixelRatio);
						int x2 = (int)((end.Longitude - minLongitude) * pixelRatio);
						graphics.DrawLine(shortestPathColor, x, y, x2, y2);
					}
				}
				Coordinate coord = shortestPath[shortestPath.Count - 1].Start as Coordinate;
				int cy = (int)((coord.Latitude - minLatitude) * pixelRatio);
				int cx = (int)((coord.Longitude - minLongitude) * pixelRatio);
				graphics.FillEllipse(startColor, cx - 2, cy - 2, 5, 5);
				coord = shortestPath[0].End as Coordinate;
				cy = (int)((coord.Latitude - minLatitude) * pixelRatio);
				cx = (int)((coord.Longitude - minLongitude) * pixelRatio);
				graphics.FillEllipse(endColor, cx - 2, cy - 2, 5, 5);
			}
			bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
			bitmap.Save(filename, ImageFormat.Png);
		}
	}
}
